<template>
  <div class="relative w-full h-full overflow-hidden">
    <TdtCesiumMap
      ref="mapRef"
      :token="mapConfig.tdtToken"
      :lon="mapConfig.center.lon"
      :lat="mapConfig.center.lat"
      :height="mapConfig.center.height"
    />
    <div class="absolute top-5 left-5 p-3 rounded-xl bg-black/40 text-white flex flex-col gap-1.5">
      <div class="text-lg font-600">人员实时位置信息</div>
      <div class="flex items-center gap-2 text-sm">
        <span class="inline-block w-2.5 h-2.5 rounded-full bg-green-400"/>
        <span>更新间隔：5 秒</span>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import {onBeforeUnmount, onMounted, ref} from 'vue';
import * as Cesium from 'cesium';
import TdtCesiumMap from '@/components/cesium/TdtCesiumMap.vue';
import {MAP_CONFIG} from '@/config/map';

const mapConfig = MAP_CONFIG;
const mapRef = ref<InstanceType<typeof TdtCesiumMap> | null>(null);
let viewer: Cesium.Viewer | null = null;
let handler: Cesium.ScreenSpaceEventHandler | null = null;
let timer: any;

interface PersonEntity {
  id: string;
  name: string;
  lon: number;
  lat: number;
  entity?: Cesium.Entity;
}

const people = ref<PersonEntity[]>([]);

const nameList = ['王伟', '李娜', '张敏', '刘洋', '陈杰', '杨静', '黄磊', '周玲', '吴涛', '赵敏'];

/* 将人员姓名与背景图片合成为一个画布图片，用于 billboard */
let nameBgImage: HTMLImageElement | null = null;
const nameBillboardCache = new Map<string, HTMLCanvasElement>();

const loadNameBgImage = (): Promise<HTMLImageElement> => {
  if (nameBgImage && nameBgImage.complete) return Promise.resolve(nameBgImage);
  return new Promise((resolve, reject) => {
    const img = new Image();
    img.src = '/images/mingzi.png';
    img.onload = () => {
      nameBgImage = img;
      resolve(img);
    };
    img.onerror = (e) => reject(e);
  });
};

const createNameBillboardCanvas = async (name: string): Promise<HTMLCanvasElement> => {
  const cached = nameBillboardCache.get(name);
  if (cached) return cached;

  const bg = await loadNameBgImage();
  const width = bg.naturalWidth || bg.width || 200;
  const height = bg.naturalHeight || bg.height || 60;
  const canvas = document.createElement('canvas');
  canvas.width = width;
  canvas.height = height;
  const ctx = canvas.getContext('2d');
  if (!ctx) return canvas;

  // 绘制背景
  ctx.clearRect(0, 0, width, height);
  ctx.drawImage(bg, 0, 0, width, height);

  // 绘制文字（自适应宽度，居中）
  const padding = 20;
  const maxTextWidth = width - padding * 2;
  let fontSize = 16;
  ctx.font = `${fontSize}px sans-serif`;
  let metrics = ctx.measureText(name);
  if (metrics.width > maxTextWidth) {
    fontSize = Math.max(12, Math.floor(fontSize * (maxTextWidth / metrics.width)));
    ctx.font = `${fontSize}px sans-serif`;
  }
  ctx.fillStyle = '#FFFFFF';
  ctx.textAlign = 'center';
  ctx.textBaseline = 'middle';
  ctx.fillText(name, width / 2, height / 2);

  nameBillboardCache.set(name, canvas);
  return canvas;
};

/* 根据中心点生成随机人员分布 */
const spawnPeople = (centerLon: number, centerLat: number) => {
  const count = Math.floor(Math.random() * 5) + 6; // 6-10人
  const generated: PersonEntity[] = [];
  for (let i = 0; i < count; i++) {
    const offsetLon = (Math.random() - 0.5) * 0.02;
    const offsetLat = (Math.random() - 0.5) * 0.02;
    generated.push({
      id: `person-${i}`,
      name: nameList[(i + Math.floor(Math.random() * nameList.length)) % nameList.length],
      lon: centerLon + offsetLon,
      lat: centerLat + offsetLat
    });
  }
  people.value = generated;
};

const loadViewer = () => {
  viewer = mapRef.value?.getViewer?.() ?? null;
  if (!viewer) return;

  handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
  handler.setInputAction(() => {
    clearSelection();
  }, Cesium.ScreenSpaceEventType.LEFT_CLICK);

  const center = mapConfig.center;
  spawnPeople(center.lon, center.lat);
  renderPeople();
  timer = setInterval(movePeople, 5000);
};

const renderPeople = () => {
  if (!viewer) return;
  viewer.entities.removeAll();
  people.value.forEach((person) => {
    person.entity = viewer!.entities.add({
      id: person.id,
      position: Cesium.Cartesian3.fromDegrees(person.lon, person.lat, 0),
      billboard: {
        image: '/images/position.png',
        scale: 0.8,
        verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
        disableDepthTestDistance: Number.POSITIVE_INFINITY
      }
    });

    const nameEntity = viewer!.entities.add({
      position: Cesium.Cartesian3.fromDegrees(person.lon, person.lat, 0),
      billboard: {
        // 先使用底图占位，异步生成带名字的画布后再替换
        image: '/images/mingzi.png',
        verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
        pixelOffset: new Cesium.Cartesian2(0, -80),
        scale: 1,
        disableDepthTestDistance: Number.POSITIVE_INFINITY,
        eyeOffset: new Cesium.Cartesian3(0, 0, 10)
      }
    });

    // 异步生成姓名+底图合成图，并替换 billboard.image
    createNameBillboardCanvas(person.name).then((canvas) => {
      if (nameEntity && nameEntity.billboard) {
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        (nameEntity.billboard as any).image = canvas;
      }
    });
  });
};

const movePeople = () => {
  people.value = people.value.map((person) => {
    const lon = person.lon + (Math.random() - 0.5) * 0.002;
    const lat = person.lat + (Math.random() - 0.5) * 0.002;
    person.lon = lon;
    person.lat = lat;
    return person;
  });
  renderPeople();
};

const clearSelection = () => {
  // 留钩子方便后续拓展
};

onMounted(() => {
  setTimeout(loadViewer, 300); // 等待地图初始化
});

onBeforeUnmount(() => {
  if (timer) clearInterval(timer);
  if (handler) handler.destroy();
  if (viewer) {
    viewer.entities.removeAll();
  }
});
</script>
